package cpu

import "fmt"

func (c *CPU) runInstruction(inst uint32) {
	op := inst & 0x7F
	fmt.Printf("inst:%x op:%x\n", inst, op)
	switch op {
	// I-TYPE, opcode: 0b0010011
	case 0x13:
		fun := (inst >> 12) & 0x7
		switch fun {
		// ADDI
		case 0x0:
			break
		// SLLI
		case 0x1:
			break
		// SLTI
		case 0x2:
			break
		// SLTIU
		case 0x3:
			break
		// XORI
		case 0x4:
			break
		// SRLT and SRAI
		case 0x5:
			break
		// ORI
		case 0x6:
			break
		// ANDI
		case 0x7:
			break
		default:
			// throw error
			break
		}
		break
	// R-TYPE, opcode: 0b0110011
	case 0x33:
		fun := (((inst >> 25) & 0x7F) << 3) | ((inst >> 12) & 0x7)
		switch fun {
		// ADD
		case 0x0:
			break
		// SUB
		case 0x100:
			break
		// SLL
		case 0x1:
			break
		// SLT
		case 0x2:
			break
		// SLTU
		case 0x3:
			break
		// XOR
		case 0x4:
			break
		// SRL
		case 0x5:
			break
		// SRA
		case 0x105:
			break
		// OR
		case 0x6:
			break
		// AND
		case 0x7:
			break
		// MUL
		case 0x8:
			break
		// MULH
		case 0x9:
			break
		// MULHSU
		case 0xA:
			break
		// MULHU
		case 0xB:
			break
		// DIV
		case 0xC:
			break
		// DIVU
		case 0xD:
			break
		// REM
		case 0xE:
			break
		// REMU
		case 0xF:
			break
		default:
			// throw error
			break
		}
		break
	// L-TYPE (LUI) - opcode: 0b0110111
	case 0x37:
		break
	// L-TYPE (AUIPC) - opcode: 0b0010111
	case 0x17:
		break
	// J-TYPE (JAL) - opcode: 0b1101111
	case 0x6F:
		break
	// B-TYPE (Branches) - opcode: 0b1100011
	case 0x63:
		fun := (inst >> 12) & 0x7
		switch fun {
		// BEQ
		case 0x0:
			break
		// BNE
		case 0x1:
			break
		// BLT
		case 0x4:
			break
		// BGE
		case 0x5:
			break
		// BLTU
		case 0x6:
			break
		// BGEU
		case 0x7:
			break
		default:
			// throw error
			break
		}
		break
	// I-TYPES (JALR)
	case 0x67:
		fun := (inst >> 12) & 0x7
		switch fun {
		case 0x0:
			break
		default:
			// throw error
			break
		}
		break
	// Loads
	case 0x3:
		fun := (inst >> 12) & 0x7
		switch fun {
		// LB
		case 0x0:
			break
		// LH
		case 0x1:
			break
		// LW
		case 0x2:
			break
		// LD
		case 0x3:
			break
		// LBU
		case 0x4:
			break
		// LHU
		case 0x5:
			break
		// LWU
		case 0x6:
			break
		default:
			// throw error
			break
		}
		break
	// Stores
	case 0x23:
		fun := (inst >> 12) & 0x7
		switch fun {
		// SB
		case 0x0:
			break
		// SH
		case 0x1:
			break
		// SW
		case 0x2:
			break
		// SD
		case 0x3:
			break
		default:
			// throw error
			break
		}
		break
	// FENCE instructions - NOPS for this imp
	case 0x0F:
		fun := (inst >> 12) & 0x7
		switch fun {
		case 0x0:
			break
		case 0x1:
			break
		default:
			// throw error
			break
		}
		break
	// R-TYPES (continued): System instructions
	case 0x73:
		fun := ((inst >> 12) & 0x7) | (((inst >> 20) & 0x1F) << 3) | (((inst >> 25) & 0x7F) << 8)
		switch fun {
		// SCALL
		case 0x0:
			break
		// SBREAK
		case 0x8:
			break
		// SRET
		case 0x4000:
			break
		// RDCYCLE
		case 0x6002:
			break
		// RDTIME
		case 0x600A:
			break
		// RDINSTRET
		case 0x6012:
			break
		default:
			fun := (inst >> 12) & 0x7
			//rs1 := c.XReg[inst >> 15] & 0x1F
			switch fun {
			// CSRRW
			case 0x1:
				break
			// CSRRS
			case 0x2:
				break
			// CSRRC
			case 0x3:
				break
			// CSRRWI
			case 0x5:
				break
			// CSRRSI
			case 0x6:
				break
			// CSRRCI
			case 0x7:
				break
			default:
				// throw error
				break
			}
			break
		}
		break
	// 32 bit integer compute instructions
	case 0x1B:
		fun := (inst >> 12) & 0x7
		switch fun {
		// ADDIW
		case 0x0:
			break
		// SLLIW
		case 0x1:
			break
		// SRLIW and SRAIW
		case 0x5:
			break
		default:
			// throw error
			break
		}
		break
	// more 32 bit int compute
	case 0x3B:
		fun := (((inst >> 25) & 0x7F) << 3) | ((inst >> 12) & 0x7)
		switch fun {
		// ADDW
		case 0x0:
			break
		// SUBW
		case 0x100:
			break
		// SLLW
		case 0x1:
			break
		// SRLW
		case 0x5:
			break
		// SRAW
		case 0x105:
			break
		// MULW
		case 0x8:
			break
		// DIVW
		case 0xC:
			break
		// DIVUW
		case 0xD:
			break
		// REMW
		case 0xE:
			break
		// REMUW
		case 0xF:
			break
		default:
			// throw error
			break
		}
		break
	// atomic memory instructions
	case 0x2F:
		fun := ((((inst >> 25) & 0x7F) >> 2) << 3) | ((inst >> 12) & 0x7)
		switch fun {
		// AMOADD.W
		case 0x2:
			break
		// AMOSWAP.W
		case 0xA:
			break
		// AMOXOR.W
		case 0x22:
			break
		// AMOAND.W
		case 0x62:
			break
		// AMOOR.W
		case 0x42:
			break
		// AMOMIN>W
		case 0x82:
			break
		// AMOMAX.W
		case 0xA2:
			break
		// AMOMINU.W
		case 0xC2:
			break
		// AMOMAXU.W
		case 0xE2:
			break
		// AMOADD.D
		case 0x3:
			break
		// AMOSWAP.D
		case 0xB:
			break
		// AMOXOR.D
		case 0x23:
			break
		// AMOAND.D
		case 0x63:
			break
		// AMOOR.D
		case 0x43:
			break
		// AMOMIN.D
		case 0x83:
			break
		// AMOMAX.D
		case 0xA3:
			break
		// AMOMINU.D
		case 0xC3:
			break
		// AMOMAXU.D
		case 0xE3:
			break
		// LR.W
		case 0x12:
			break
		// LR.D
		case 0x13:
			break
		// SC.W
		case 0x1A:
			break
		// SC.D
		case 0x1B:
			break
		default:
			// throw error
			break
		}
		break
		// Floating-Point Memory Insts, FLW, FLD
	case 0x7:
	case 0x27:
	case 0x43:
	case 0x47:
	case 0x4B:
	case 0x4F:
	case 0x53:
		// throw error
		break
	default:
		//throw new RISCVError("Unknown instruction at: 0x" + RISCV.pc.toString(16));
		//don't throw error for completely unknown inst (i.e. unknown opcode)
		// throw error
		break
	}

	// force x0 (zero) to zero
	c.XReg[0] = 0
	// finally, increment cycle counter, instret counter, count register:
	c.PCR[CSR_CYCLE.Index] += 1
	c.PCR[CSR_COUNT.Index] += 1
}
